package hikari.utils;

/**
 * @author Otaka
 */
public class Vector {

    private double x;
    private double y;

    public Vector() {
        x = 0;
        y = 0;
    }

    public Vector(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public Vector(Vector v) {
        this.x = v.x;
        this.y = v.y;
    }

    @Override
    public Vector clone() {
        Vector v = new Vector();
        v.x = x;
        v.y = y;
        return v;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }

    public Vector summ(Vector v) {
        setX(getX() + v.getX());
        setY(getY() + v.getY());
        return this;
    }
    
    public Vector subtract(Vector v){
        setX(getX() - v.getX());
        setY(getY() - v.getY());
        return this;
    }

    public Vector scalarMultiple(double value) {
        setX(getX() * value);
        setY(getY() * value);
        return this;
    }

    public double scalarMultiple(Vector v) {
        return getX() * v.getX() + getY() * v.getY();
    }

    public Vector convertToUnitVector() {
        scalarMultiple(1.0 / length());
        return this;
    }

    public Vector getVectorProjection(Vector v) {
        v = v.clone();
        v.convertToUnitVector();
        double projectionLength = scalarMultiple(v);
        return v.scalarMultiple(projectionLength);
    }

    public Vector getVectorNormal() {
        Vector n = clone();
        double tX = getX();
        n.setX(0 - y);
        n.setY(tX);
        return n;
    }

    /**
     * @param v
     * v:vector-surface that reflect the vector
     * @return 
     * this
     */
    public Vector reflectVector(Vector mirror) {
        Vector norm = mirror.getVectorNormal();
        norm.scalarMultiple(-1);
        norm.convertToUnitVector();
        Vector projection = getVectorProjection(norm);
        projection.scalarMultiple(-2);
        summ(projection);
        return this;
    }
    
    public Vector setVectorLength(double length){
        convertToUnitVector();
        scalarMultiple(length);
        return this;
    }

    public double length() {
        return Math.sqrt(getX() * getX() + getY() * getY());
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Vector other = (Vector) obj;
        if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
            return false;
        }
        if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
        hash = 97 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
        return hash;
    }

    @Override
    public String toString() {
        return "x="+x+",   y="+y;
    }
    
    
} 